// =============================================
// 该代码段通常位于一个 HLSL 文件（如 FractalGPU.hlsl）中，
// 用于支持 GPU Instancing（实例化渲染）的功能，
// 包括：
// 1. 从 CPU 传入的每实例变换矩阵（float3x4）的设置
// 2. 基于 InstanceID 的动态颜色计算
// 3. 提供给 Shader Graph 使用的接口函数
// =============================================

// ----------------------------------------------------------------
// 条件编译：仅在启用了 Unity 的「程序化实例化（Procedural Instancing）」时编译下面的矩阵设置代码
// UNITY_PROCEDURAL_INSTANCING_ENABLED 是 Unity 在启用 GPU Instancing 时自动定义的宏
// ----------------------------------------------------------------
#if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)

    // 声明一个 StructuredBuffer（结构化缓冲区），用于接收从 CPU（比如 C# 脚本）传递过来的矩阵数据
    // 每个元素是一个 float3x4 类型的矩阵，代表一个渲染实例的“物体空间 -> 世界空间”变换
    // 该缓冲区一般通过 ComputeBuffer 上传，并在 Shader 中通过 _Matrices 名称访问
    StructuredBuffer<float3x4> _Matrices;

#endif


// ----------------------------------------------------------------
// 函数：ConfigureProcedural()
// 作用：这是一个特殊的函数，由 Unity 在「程序化实例化模式」下自动调用，
//       用于为当前正在绘制的实例设置其「物体到世界空间」的变换矩阵（unity_ObjectToWorld）
//       它会在每个实例的顶点着色器执行之前运行。
// ----------------------------------------------------------------
void ConfigureProcedural () {
    #if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)

        // 从 _Matrices 缓冲区中，根据当前实例的 ID（unity_InstanceID）取出对应的变换矩阵
        // unity_InstanceID 是 Unity 自动提供的，表示当前正在处理的实例索引（从 0 开始）
        float3x4 m = _Matrices[unity_InstanceID];

        // 设置第 1 行（X 轴相关变换）
        unity_ObjectToWorld._m00_m01_m02_m03 = m._m00_m01_m02_m03;

        // 设置第 2 行（Y 轴相关变换）
        unity_ObjectToWorld._m10_m11_m12_m13 = m._m10_m11_m12_m13;

        // 设置第 3 行（Z 轴相关变换）
        unity_ObjectToWorld._m20_m21_m22_m23 = m._m20_m21_m22_m23;

        unity_ObjectToWorld._m30_m31_m32_m33 = float4(0.0, 0.0, 0.0, 1.0);

    #endif
}


// ----------------------------------------------------------------
// Shader 属性：两个颜色参数，通常由 Material 或 C# 脚本传入
// 用于在 GetFractalColor() 函数中插值生成每个实例的最终颜色
// ----------------------------------------------------------------
float4 _ColorA, _ColorB;

// 一个四维向量，可能用于控制颜色插值的随机种子或参数
// 通常由 C# 端通过 MaterialPropertyBlock 传入
float4 _SequenceNumbers;


// ----------------------------------------------------------------
// 函数：GetFractalColor()
// 作用：基于当前实例的 ID（unity_InstanceID）和 _SequenceNumbers，
//       使用 frac() 函数生成一个伪随机因子，从而在 _ColorA 和 _ColorB 之间插值，
//       实现每个实例显示不同颜色的效果（程序化颜色分配）
//       该函数返回一个 float4 颜色值（RGBA）
// ----------------------------------------------------------------
float4 GetFractalColor () {
    
    #if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)

        float4 color;

        // 在 _ColorA.rgb 和 _ColorB.rgb 之间插值，插值因子为：
        // frac(unity_InstanceID * _SequenceNumbers.x + _SequenceNumbers.y)
        // 这个表达式利用了实例的唯一 ID 和随机种子，使得每个实例获得不同的插值比例
        // 结果是一个 [0,1) 范围内的伪随机数，用于控制颜色 A <-> B 的混合比例
        color.rgb = lerp(
            _ColorA.rgb, _ColorB.rgb,
            frac(unity_InstanceID * _SequenceNumbers.x + _SequenceNumbers.y)
        );

        // 同样的方式插值透明度（Alpha）
        color.a = lerp(
            _ColorA.a, _ColorB.a,
            frac(unity_InstanceID * _SequenceNumbers.z + _SequenceNumbers.w)
        );

        // 返回最终插值颜色
        return color;

    #else
        // 如果不是程序化实例化模式（比如普通渲染），直接返回颜色 A
        return _ColorA;
    #endif
}


// ----------------------------------------------------------------
// 函数：ShaderGraphFunction_float
// 作用：这是一个兼容 Shader Graph 的函数，输入一个 float3，输出 float3 和 float4（颜色）
//       它将输入原样输出，并附加一个通过 GetFractalColor() 得到的颜色
//       通常用于在 Shader Graph 中调用，作为自定义节点的一部分
// ----------------------------------------------------------------
void ShaderGraphFunction_float (float3 In, out float3 Out, out float4 FractalColor) {
    Out = In; // 原样输出输入向量
    FractalColor = GetFractalColor(); // 计算并输出当前实例的颜色
}

// ----------------------------------------------------------------
// 函数：ShaderGraphFunction_half
// 作用：与上面函数类似，但是使用的是半精度浮点（half），用于移动端等优化场景
// ----------------------------------------------------------------
void ShaderGraphFunction_half (half3 In, out half3 Out, out half4 FractalColor) {
    Out = In; // 原样输出输入向量
    FractalColor = GetFractalColor(); // 计算并输出当前实例的颜色
}